//
//  ZTDataManager.m
//  CoreDataLearn
//
//  Created by zhoutong on 17/4/12.
//  Copyright © 2017年 tong. All rights reserved.
//

#import "ZTDataManager.h"
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>

static ZTDataManager *shareDataManager = nil;

@interface ZTDataManager ()

//iOS9中 CoreData Stack核心的三个类
//管理模型文件上下文
@property(nonatomic,strong)NSManagedObjectContext *managedObjectContext1;
//模型文件
@property(nonatomic,strong)NSManagedObjectModel *managedObjectModel;
//存储调度器
@property(nonatomic,strong)NSPersistentStoreCoordinator *persistentStoreCoordinator;

//iOS10中NSPersistentContainer
/**
 CoreData Stack容器
 内部包含：
 管理对象上下文：NSManagedObjectContext *viewContext;
 对象管理模型：NSManagedObjectModel *managedObjectModel
 存储调度器：NSPersistentStoreCoordinator *persistentStoreCoordinator;
 */
@property(nonatomic,strong)NSPersistentContainer *persistentContainer;

@end

@implementation ZTDataManager
@synthesize persistentContainer = _persistentContainer;

#pragma mark -- 增删改查

- (BOOL)addData:(addDataBlock)block{
    return [self addData:block withEntityName:NAME_Entity];
}

- (BOOL)addData:(addDataBlock)block withEntityName:(NSString*)entityName{
    
    NSManagedObject *obj = [NSEntityDescription insertNewObjectForEntityForName:entityName inManagedObjectContext:shareDataManager.managedObjectContext];
    block(obj);
    return [self saveContext];
}

- (BOOL)updateData{
    return [self saveContext];
}

- (BOOL)deleteData:(NSArray<__kindof NSManagedObject *>*)dataArr{
    
    for (__kindof NSManagedObject *obj in dataArr) {
        [self.managedObjectContext deleteObject:obj];
    }
    return [self saveContext];
}

- (NSArray*)selectData:(NSPredicate*)predicate andSortType:(NSArray<NSSortDescriptor *>*)sortType{
    return [self selectData:predicate andSortType:sortType entityName:NAME_Entity];
}

- (NSArray*)selectData:(NSPredicate*)predicate andSortType:(NSArray<NSSortDescriptor *>*)sortType entityName:(NSString*)entityName{
    
    NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:entityName];
    if (sortType) {
        request.sortDescriptors = sortType;
    }
    if (predicate) {
        [request setPredicate:predicate];
    }
    NSError *error = nil;
    NSArray *resultArr = [self.managedObjectContext executeFetchRequest:request error:&error];
    
    return resultArr;
}

#pragma mark -iOS9 CoreData Stack

//获取沙盒路径URL
-(NSURL*)getDocumentsURL
{
    return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
}
//懒加载managedObjectModel
- (NSManagedObjectModel *)managedObjectModel
{
    if (_managedObjectModel != nil) {
        return _managedObjectModel;
    }
    /**
     根据某个模型文件路径创建模型文件
     _managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:[[NSBundle mainBundle]URLForResource:@"Person" withExtension:@"momd"]];
     
     合并Bundle所有.momd文件
     budles: 指定为nil,自动从mainBundle里找所有.momd文件
     */
    _managedObjectModel = [NSManagedObjectModel mergedModelFromBundles:nil];
    
    return _managedObjectModel;
}

//懒加载persistentStoreCoordinator
-(NSPersistentStoreCoordinator*)persistentStoreCoordinator
{
    if (_persistentStoreCoordinator != nil) {
        return _persistentStoreCoordinator;
    }
    //根据模型文件创建存储调度器
    _persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:self.managedObjectModel];
    /**
     *  给存储调度器添加存储器
     *
     *  tyep:存储类型
     *  configuration：配置信息 一般为nil
     *  options：属性信息  一般为nil
     *  URL：存储文件路径
     */
    NSURL *url = [[self getDocumentsURL] URLByAppendingPathComponent:[NSString stringWithFormat:@"%@.sqlite",NAME_xcdatamodel]];
    [_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:url options:nil error:nil];
//    NSLog(@"%@",_persistentStoreCoordinator.persistentStores[0].URL);
    
    return _persistentStoreCoordinator;
}

//懒加载managedObjectContext
-(NSManagedObjectContext*)managedObjectContext1
{
    if (_managedObjectContext1 != nil) {
        return _managedObjectContext1;
    }
    //参数表示线程类型  NSPrivateQueueConcurrencyType比NSMainQueueConcurrencyType略有延迟
    _managedObjectContext1 = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
    
    //设置存储调度器
    [_managedObjectContext1 setPersistentStoreCoordinator:self.persistentStoreCoordinator];
    
    return _managedObjectContext1;
}

#pragma mark -iOS10 CoreData Stack

- (NSPersistentContainer *)persistentContainer {
    // The persistent container for the application. This implementation creates and returns a container, having loaded the store for the application to it.
    @synchronized (self) {
        if (_persistentContainer == nil) {
            _persistentContainer = [[NSPersistentContainer alloc] initWithName:NAME_xcdatamodel];
            [_persistentContainer loadPersistentStoresWithCompletionHandler:^(NSPersistentStoreDescription *storeDescription, NSError *error) {
                if (error != nil) {
                    // Replace this implementation with code to handle the error appropriately.
                    // abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
                    
                    /*
                     Typical reasons for an error here include:
                     * The parent directory does not exist, cannot be created, or disallows writing.
                     * The persistent store is not accessible, due to permissions or data protection when the device is locked.
                     * The device is out of space.
                     * The store could not be migrated to the current model version.
                     Check the error message to determine what the actual problem was.
                     */
                    NSLog(@"Unresolved error %@, %@", error, error.userInfo);
                    abort();
                }
            }];
        }
    }
    
    return _persistentContainer;
}

- (NSPersistentContainer *)getCurrentPersistentContainer
{
    //获取系统版本
    float systemNum = [[UIDevice currentDevice].systemVersion floatValue];
    //根据系统版本返回不同的NSManagedObjectContext
    if(systemNum < 10.0){
        return nil;
    }else{
        return shareDataManager.persistentContainer;
    }
}

#pragma mark - NSManagedObjectContext

- (NSManagedObjectContext *)managedObjectContext
{
    //获取系统版本
    float systemNum = [[UIDevice currentDevice].systemVersion floatValue];
    
    //根据系统版本返回不同的NSManagedObjectContext
    if(systemNum < 10.0){
        return shareDataManager.managedObjectContext1;
    }else{
        return shareDataManager.persistentContainer.viewContext;
    }
}

#pragma mark -- saveContext

- (BOOL)saveContext {
    NSManagedObjectContext *context = [self managedObjectContext];
    
    NSError *error = nil;
    
    BOOL isChange = [context hasChanges];
    BOOL isSave = [context save:&error];
    if (isChange && !isSave) {
        // Replace this implementation with code to handle the error appropriately.
        // abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
        NSLog(@"Unresolved error %@, %@", error, error.userInfo);
        abort();
    }
    return isSave;
}
#pragma mark -- 单利

+ (ZTDataManager*)shareDataManager{
    @synchronized (self) {
        if (nil == shareDataManager) {
            shareDataManager = [[ZTDataManager alloc] init];
        }
    }
    return shareDataManager;
}

+ (instancetype)allocWithZone:(struct _NSZone *)zone{
    if (nil == shareDataManager) {
        shareDataManager = [super allocWithZone:zone];
    }
    return shareDataManager;
}



@end
